<template>
    <div class="scanner-container">
        <video ref="videoRef" class="video-preview"></video>
        <div class="scan-overlay"></div>
        <div v-if="statusText" class="status">{{ statusText }}</div>
        <div class="footer-main">
            <button @click="handlePhotoScan" class="photo-btn">扫码有问题?点我拍照识别</button>
            <button @click="handleCancelScan" class="cancel-btn">取消</button>
            <input ref="fileInputRef" type="file" accept="image/*" capture="environment" @change="handleFileSelect" style="display: none;" />
        </div>
    </div>
</template>

<script setup lang="ts">
import {ref, onMounted, onBeforeUnmount} from 'vue';
import {BrowserMultiFormatReader, type Result} from '@zxing/library';
import {showDialog} from "vant";

const emit = defineEmits<{
    (e: 'scan-success', isbn: string): void
    (e: 'scan-error', error: Error): void
    (e: 'scan-cancel'): void
}>();

const videoRef = ref<HTMLVideoElement | null>(null);
const fileInputRef = ref<HTMLInputElement | null>(null);
// 使用更长的超时时间初始化读取器
const codeReader = new BrowserMultiFormatReader(undefined, 5000);
const statusText = ref<string>('正在初始化摄像头...');
let scanTimer: number | null = null;

// ISBN校验函数
const validateISBN = (code: string): boolean => {
    if (code.length !== 13 && code.length !== 10) return false;
    // 这里可以添加更详细的校验逻辑
    return /^\d+$/.test(code);
};
// 添加节流函数
let isScanning = false;
// 开始扫描
const startScan = async () => {
    try {
        // 更新状态文本
        statusText.value = '正在获取摄像头列表...';
        console.log('开始获取摄像头设备列表');
        const devices = await codeReader.listVideoInputDevices();
        if (!devices || devices.length === 0) {
            throw new Error('未检测到摄像头设备');
        }
        statusText.value = '正在启动摄像头...';
        let constraints = {
            video: {
                deviceId: devices[0].deviceId,
                facingMode: 'environment',
                width: {ideal: 640},
                height: {ideal: 360},
                zoom: 3,
            },
            audio: false,
        };
        const backCameraId = await getBackCamera();
        if (backCameraId) {
            constraints.video.deviceId = backCameraId;
        }
        videoRef.value.srcObject = await navigator.mediaDevices.getUserMedia(constraints);
        videoRef.value.onloadedmetadata = () => {
            statusText.value = '摄像头已就绪，识别中...';
            // 确保视频播放成功后再启动扫描
            videoRef.value.play().then(() => {
                animationFrameId = requestAnimationFrame(scanFrame);
            }).catch(err => console.error('视频播放失败:', err));
        };
    } catch (error) {
        console.error('摄像头初始化失败:', error);
        emit('scan-error', new Error('摄像头初始化失败'));
    }
};

let lastScanTime = 0;
let animationFrameId: number | null = null;
const SCAN_INTERVAL = 1000; // 2秒扫描一次
const scanFrame = async (timestamp: number) => {
    // 如果上一次扫描还未完成，则跳过本次扫描
    if (isScanning) {
        console.log('上一次扫描尚未完成，跳过本次扫描');
        return;
    }
    // 检查是否到达扫描间隔
    if (timestamp - lastScanTime >= SCAN_INTERVAL) {
        lastScanTime = timestamp;
        // 扫描逻辑...
        if (!videoRef.value || !videoRef.value.srcObject) {
            console.warn('视频元素或媒体流不存在，跳过扫描');
        } else {
            try {
                isScanning = true;
                const result = await codeReader.decodeOnce(videoRef.value);
                if (result && validateISBN(result.getText())) {
                    console.log('成功扫描到ISBN:', result.getText());
                    emit('scan-success', result.getText());
                    stopScan();
                    return; // 扫描成功后停止动画帧
                }
            } catch (error) {
                console.log('未识别到条码或ISBN无效:', error);
            } finally {
                isScanning = false;
            }
        }
    }
    // 仅当未停止时才继续请求下一帧
    if (animationFrameId !== null) {
        animationFrameId = requestAnimationFrame(scanFrame);
    }
};

const handleCancelScan = () => {
    stopScan()
    emit('scan-cancel');
};

// 处理拍照识别按钮点击
const handlePhotoScan = () => {
    // 先停止摄像头扫描
    stopScan();
    statusText.value = '请选择图片或拍照...';
    // 触发文件选择
    if (fileInputRef.value) {
        fileInputRef.value.click();
    }
};

// 处理文件选择
const handleFileSelect = async (event: Event) => {
    const target = event.target as HTMLInputElement;
    const file = target.files?.[0];

    if (!file) {
        statusText.value = '未选择文件';
        return;
    }

    try {
        statusText.value = '正在识别图片中的条码...';

        // 创建图片元素
        const img = new Image();
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');

        img.onload = async () => {
            // 设置canvas尺寸
            canvas.width = img.width;
            canvas.height = img.height;

            // 绘制图片到canvas
            ctx?.drawImage(img, 0, 0);

            try {
                // 使用ZXing识别条码
                const result = await codeReader.decodeFromImageElement(img);

                if (result && validateISBN(result.getText())) {
                    console.log('图片识别成功，ISBN:', result.getText());
                    statusText.value = '识别成功!';
                    emit('scan-success', result.getText());
                } else {
                    statusText.value = '未识别到有效的ISBN条码，请重新选择图片';
                }
            } catch (error) {
                console.error('图片识别失败:', error);
                statusText.value = '识别失败，请尽量确保图片中包含清晰的条码';
            }
        };

        img.onerror = () => {
            statusText.value = '图片加载失败，请重新选择';
        };

        // 读取文件并设置图片源
        const reader = new FileReader();
        reader.onload = (e) => {
            img.src = e.target?.result as string;
        };
        reader.readAsDataURL(file);

    } catch (error) {
        console.error('处理文件时出错:', error);
        statusText.value = '处理文件时出错，请重试';
    } finally {
        // 清空文件输入，允许重复选择同一文件
        if (target) {
            target.value = '';
        }
    }
};

const getBackCamera = async () => {
    const devices = await navigator.mediaDevices.enumerateDevices();
    const videoDevices = devices.filter(device => device.kind === 'videoinput');
    // 尝试找到后置摄像头
    const backCamera = videoDevices.find(device =>
        device.label.toLowerCase().includes('back') ||
        device.label.toLowerCase().includes('rear') ||
        device.label.toLowerCase().includes('环境') ||
        device.label.toLowerCase().includes('后置')
    );
    return backCamera ? backCamera.deviceId : null;
};

// 停止扫描
const stopScan = () => {
    if (animationFrameId !== null) {
        cancelAnimationFrame(animationFrameId);
        animationFrameId = null;
        console.log('动画帧已取消');
    }
    console.log('正在停止扫描...');
    // 清除扫描定时器
    if (scanTimer) {
        clearInterval(scanTimer);
        scanTimer = null;
        console.log('扫描定时器已清除');
    }
    // 停止所有媒体轨道
    if (videoRef.value?.srcObject) {
        // 释放 codeReader 资源
        try {
            codeReader.reset();
            console.log('条码读取器已重置');
        } catch (error) {
            console.error('重置条码读取器时出错:', error);
        }
        try {
            const stream = videoRef.value.srcObject as MediaStream;
            const tracks = stream.getTracks();
            console.log(`停止 ${tracks.length} 个媒体轨道`);
            tracks.forEach(track => {
                track.stop();
                console.log(`已停止轨道: ${track.kind}`);
            });
            // 清除视频源
            videoRef.value.srcObject = null;
            console.log('视频源已清除');
        } catch (error) {
            console.error('停止媒体轨道时出错:', error);
        }
    } else {
        console.log('没有活动的媒体流需要停止');
    }
    statusText.value = '扫描已停止';
};

// 组件挂载时初始化摄像头
onMounted(() => {
    console.log('组件已挂载，准备初始化摄像头');
    try {
        // 使用setTimeout确保DOM完全渲染后再初始化摄像头
        setTimeout(() => {
            if (!videoRef.value) {
                console.error('视频元素未正确绑定');
                return;
            }
            startScan().catch(error => {
                console.error('摄像头初始化失败:', error);
                statusText.value = `初始化失败: ${error instanceof Error ? error.message : '未知错误'}`;
            });
        }, 300);
    } catch (error) {
        console.error('挂载阶段出错:', error);
    }
});
// 组件卸载前释放摄像头资源
onBeforeUnmount(() => {
    console.log('组件即将卸载，释放摄像头资源');
    try {
        stopScan();
    } catch (error) {
        console.error('卸载阶段释放资源出错:', error);
    }
});
</script>

<style scoped>
.scanner-container {
    max-width: 640px;
    margin: 0 auto;
    position: fixed;
    top: 15%;
    width: 90%;
    left: 50%;
    transform: translateX(-50%);
    box-shadow: 0 0 20px rgb(0 0 0 / 30%);
    border-radius: 12px;
    overflow: hidden;
    font-size: 0;
    height: 466px;
}

.video-preview {
    width: 100%;
    height: 466px;
    background: #000;
}

.scan-overlay {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 70%;
    height: 20%;
    border: 3px solid #4CAF50;
    box-shadow: 0 0 20px rgba(76, 175, 80, 0.5);
}

.status {
    position: absolute;
    top: 50px;
    width: 100%;
    text-align: center;
    color: #fff;
    font-size: 16px;
    text-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
}

.footer-main {
    position: absolute;
    bottom: 20px;
    text-align: center;
    width: 100%;
    height: 80px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
}
.cancel-btn{
    width: 100px;
    height: 30px;
    font-size: 12px;
    color: #ffffff;
    background-color: #00000000;
    border: 1px solid white;
    border-radius: 6px;
    cursor: pointer;
}
.photo-btn {
    width: 200px;
    height: 36px;
    font-size: 12px;
    color: #ffffff;
    background-color: rgba(76, 175, 80, 0.8);
    border: 1px solid #4CAF50;
    border-radius: 8px;
    cursor: pointer;
    transition: all 0.3s ease;
}
.photo-btn:hover {
    background-color: rgba(76, 175, 80, 1);
    transform: translateY(-1px);
}
.photo-btn:active {
    transform: translateY(0);
}
</style>
